_Pragma("once");

#include <unistd.h>

#include <sstream>
#include <memory>
#include <mutex>

#include "HalUtility.h"
#include "DeviceCommunicator.h"
#include "ErrorCode.h"



class DummyChannel {
public:
    using Mutex = std::recursive_mutex;


    /** Default constructor */
    DummyChannel(const int channel, DeviceCommunicator& communicator) : mcommunicator(communicator), mchannel(channel) {
        mexceptionTip = mcommunicator.deviceName;
        mexceptionTip.append(",channel:");
        mexceptionTip.append(1, '0' + mchannel);
    }
    /** Default destructor */
    virtual ~DummyChannel() {
    }



    virtual std::string& sendStringReturnString(const std::string& parameter, std::string& result) {
        LOG_DEDUG("%s,sendStringReturnString:parameter:%s", mexceptionTip.data(), parameter.data());
        std::unique_lock<Mutex> locker(getMutex());
        ssize_t length = write(parameter);
        length = read(result);
        locker.unlock();

        LOG_DEDUG("%s,sendStringReturnString:result:%s", mexceptionTip.data(), result.data());
        return result;
    }


    virtual ssize_t read(std::string& result) {
        ssize_t returnCode = mcommunicator.read(mexceptionTip, mcommunicator.mbuffer, sizeof (mcommunicator.mbuffer));
        if (0 > returnCode) {
            BUILD_EXCEPTION_ERROR(FirmwareError::CHANNEL_COMM_ERROR, returnCode, errno, mexceptionTip);
        }
        result.assign(reinterpret_cast<typename std::string::const_pointer>(mcommunicator.mbuffer), returnCode);
        return returnCode;
    }

    virtual ssize_t write(const std::string& data) {

        ssize_t result = mcommunicator.write(mexceptionTip, data.data(), data.size());

        if (0 > result) {
            BUILD_EXCEPTION_ERROR(FirmwareError::CHANNEL_COMM_ERROR, result, errno, mexceptionTip);
        }

        return result;
    }

    virtual ssize_t read(void* buffer, size_t length) {
        ssize_t returnCode = mcommunicator.read(mexceptionTip, buffer, length);
        if (0 > returnCode) {
            BUILD_EXCEPTION_ERROR(FirmwareError::CHANNEL_COMM_ERROR, returnCode, errno, mexceptionTip);
        }
        return returnCode;
    }

    virtual ssize_t write(void* data, size_t length) {

        ssize_t result = mcommunicator.write(mexceptionTip, data, length);

        if (0 > result) {
            BUILD_EXCEPTION_ERROR(FirmwareError::CHANNEL_COMM_ERROR, result, errno, mexceptionTip);
        }

        return result;
    }

    virtual Mutex& getMutex() {
        return mmutex;
    }

    virtual std::ostringstream& toString(std::ostringstream& output) {
        output << mexceptionTip;

        return output;
    }

    bool operator==(const DummyChannel& rhs) {
        return mchannel == rhs.mchannel && &mcommunicator == &rhs.mcommunicator;
    }


    DeviceCommunicator& mcommunicator;
    const int mchannel;

    std::string mexceptionTip;

    Mutex mmutex;//std::mutex
};


typedef std::unique_ptr<DummyChannel> ChannelUniquePtr;

